from io import BytesIO
import time
import numpy as np
from PIL import Image
from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait


class HeiMaTouTiao:
    def __init__(self):
        self.url = 'http://mis-toutiao-python.itheima.net/#/'
        self.driver = webdriver.Chrome()
        self.driver.maximize_window()

    # 登录
    def login(self):
        while not self.check_login():
            self.driver.get(self.url)
            self.driver.find_element(By.CLASS_NAME,'yzm_btn').click()
            # 单击"点击按钮进行验证"， 弹出滑动验证码
            WebDriverWait(self.driver, 20).until(
                EC.element_to_be_clickable((
                    By.CLASS_NAME, 'geetest_radar_tip')))
            self.driver.find_element(By.CLASS_NAME,
                'geetest_radar_tip').click()
            WebDriverWait(self.driver, 20).until(
                EC.presence_of_element_located((By.CLASS_NAME, 'geetest_canvas_img')))
            # 执行js 改变css样式  获取页面所有画布 canvas
            self.driver.execute_script("document.querySelectorAll('canvas')[2].style='display:block'")
            time.sleep(1)
            # 截取不包含缺口图片
            image1 = self.get_image('verify_code1.png')
            self.driver.execute_script("document.querySelectorAll('canvas')[2].style='display:none'")
            time.sleep(1)
            self.driver.execute_script(
                "document.getElementsByClassName('geetest_canvas_slice geetest_absolute')[0].style='display:none;'")
            time.sleep(1)
            # 截取包含缺口图片
            image2 = self.get_image('verify_code2.png')
            self.driver.execute_script(
                "document.getElementsByClassName('geetest_canvas_slice geetest_absolute')[0].style='display:block;'")
            self.get_move()

    # 截取图片
    def get_image(self, image_file_name):
        # 定位图片元素
        image = self.driver.find_element(By.CLASS_NAME,'geetest_canvas_img')
        # 获取图片左上角坐标，即A点坐标
        location = image.location
        # 获取验证码图片的宽高
        size = image.size
        x1, y1 = location["x"], location["y"]
        # 通过验证码图片的宽高，与A点坐标相加，计算出C点坐标
        x2, y2 = location["x"] + size["width"], location["y"] + size["height"]
        # 截取当前网页图片
        screen_shot = self.driver.get_screenshot_as_png()
        screen_shot = Image.open(BytesIO(screen_shot))
        # 通过Image模块中crop()方法，切割出验证码图片
        captcha = screen_shot.crop((int(x1), int(y1), int(x2), int(y2)))
        captcha.save(image_file_name)
        return captcha

    # 对比图片，指定图片误差范围
    def compare_pixel(self, image1, image2, x, y):
        pixel1 = image1.load()[x, y]  # 加载图片的x,y   pixel1 是图片的像素点
        pixel2 = image2.load()[x, y]  # 加载图片的x,y
        # 范围误差
        threashold = 30
        # 像素RGB
        if abs(pixel1[0] - pixel2[0]) < threashold and abs(pixel1[1] - pixel2[1]) < threashold and abs(
                pixel1[2] - pixel2[2]) < threashold:
            return True
        else:
            return False

    # 计算滑块距离
    def get_distance(self):
        image1 = Image.open('verify_code1.png')
        image2 = Image.open('verify_code2.png')
        for i in range(image1.size[0]):
            for j in range(image1.size[1]):
                if not self.compare_pixel(image1, image2, i, j):
                    left = i
                    return left

    # 定义缓动函数
    # def ease_out_expo(self, x):
    #     if x == 1:
    #         return 1
    #     else:
    #         return 1 - pow(2, -10 * x)

    # 缓动函数
    def ease_out_quint(self,x):
        return 1 - pow(1 - x, 5)
    # 生成滑动轨迹
    def get_tracks(self, distance, seconds, ease_func):
        tracks = [0]
        offsets = [0]
        for t in np.arange(0.0, seconds, 0.1):
            ease = ease_func
            # offset 滑动的距离
            offset = round(ease(t / seconds) * distance)
            tracks.append(offset - offsets[-1])
            offsets.append(offset)
        return tracks

    # 移动滑块
    def get_move(self):
        slider = self.driver.find_element(By.CLASS_NAME,'geetest_slider_button')
        tracks = self.get_tracks(self.get_distance(),0.5, self.ease_out_quint)
        ActionChains(self.driver).click_and_hold(slider).perform()
        # 循环
        for x in tracks:
            ActionChains(self.driver).move_by_offset(xoffset=x, yoffset=0).perform()
        # 松开鼠标
        ActionChains(self.driver).pause(0.5).release().perform()
        time.sleep(2)

    # 验证是否成功
    def check_login(self):
        try:
            button = self.driver.find_element(By.CLASS_NAME,'input_sub')
            # 判断登录按钮是否可用
            if button.is_enabled():
                button.click()
                time.sleep(3)
                self.driver.close()
                return True
        except Exception as e:
            return False


if __name__ == '__main__':
    heima = HeiMaTouTiao()
    heima.login()
